package game;

import effect.character.area.AreaCharacterEffect;
import action.ActionAttack;
import board.Tile;
import character.CharacterCombatControl;
import character.CharacterStatusType;
import effect.character.single.SingleCharacterEffect;
import effect.Effect;
import character.MyCharacter;
import character.ai.AIGeneralControl;
import com.jme3.math.FastMath;
import effect.AreaEffect;
import effect.tile.TileEffect;
import game.combat.CombatActor;
import java.util.Collection;
import java.util.LinkedList;
import misc.Vector3i;
import player.AIPlayer;
import player.JournalEntry;

public abstract class CombatController {
    
    public static void attack(MyCharacter attacker, MyCharacter target) {
        Integer damage = attacker.getInventory().getEquippedWeapon().getBaseDamage();
        dealDamage(attacker, target, damage);
        
        DataStore.player.getJournal().addEntry(new JournalEntry(attacker+" womps "+target+" with its "+attacker.getInventory().getEquippedWeapon()+" for "+damage+" points of damage."));
    }
    
    public static void dealDamage(MyCharacter attacker, MyCharacter target, int amount) {
        target.getCharacterStatus().takeDamage(amount);
        if(target.getPlayer() instanceof AIPlayer) {
            target.getControl(AIGeneralControl.class).getThreatSystem().generateThreat(attacker, amount);
        }
    }
    
    public static void heal(MyCharacter healer, MyCharacter target, int amount) {
        target.getCharacterStatus().heal(amount);
    }

    public static void characterMoving(MyCharacter character) {
	for(MyCharacter potentialAttacker : DataStore.combatAppState.getCombatActorCharacters()) {
	    if(!potentialAttacker.getPlayer().equals(character.getPlayer())
                    && potentialAttacker.getPlayer().getRelationship(character.getPlayer()) == PlayerRelationship.HOSTILE
                    && potentialAttacker.getCharacterStatus().getCharacterStatusType() != CharacterStatusType.DEAD
                    && !potentialAttacker.getControl(CharacterCombatControl.class).hasQueuedAction()
                    && potentialAttacker.getControl(CharacterCombatControl.class).hasAttackOfOpportunity()
                    && CombatUtil.checkAttackRange(potentialAttacker, character)) {
                queueAttackOfOpportunity(potentialAttacker, character);
                potentialAttacker.getControl(CharacterCombatControl.class).useAttackOfOpportunity();
	    }
	}
    }

    public static void queueAttackOfOpportunity(MyCharacter attacker, MyCharacter target) {
	System.out.println("Queueing attack of opportunity for character: "+attacker);
	int attackTicks = Math.round(FastMath.ceil((float)attacker.getInventory().getEquippedWeapon().getBaseSpeed() / 2f));
	attacker.getControl(CharacterCombatControl.class).queueActionFirst(new ActionAttack(true, attacker, target, attackTicks));
	DataStore.combatAppState.registerTemporaryResolutionListener(attacker.getControl(CharacterCombatControl.class));
    }

    public static void executeEffect(Effect effect) {
	DataStore.board.addParticleEffect(effect.getParticleEffect(), effect.getParticleEffectTime());
	if(effect instanceof AreaEffect) {
	    for(Vector3i affectedLocation : ((AreaEffect)effect).getAffectedLocations()) {
		if(effect instanceof AreaCharacterEffect) {
		    for(MyCharacter character : DataStore.board.getCharactersAtLocation(affectedLocation)) {
			((AreaCharacterEffect)effect).applyEffect(character);
		    }
		} else if(effect instanceof TileEffect) {
		    Tile tile = DataStore.board.getTile(affectedLocation);
		    ((TileEffect)effect).applyEffect(tile);
		}
	    }
	} else if(effect instanceof SingleCharacterEffect) {
	    ((SingleCharacterEffect)effect).applyEffect();
	}
    }
    
    public static void characterDied(MyCharacter character) {
        if(StateSwitcher.getGameState() == GameState.COMBAT) {
            boolean endCombat = true;
            Collection<MyCharacter> combatCharacters = DataStore.combatAppState.getCombatActorCharacters();
            for(MyCharacter combatChar : combatCharacters) {
                if(combatChar.getCharacterStatus().getCharacterStatusType() != CharacterStatusType.DEAD && combatChar.getPlayer().getRelationship(DataStore.player) == PlayerRelationship.HOSTILE)
                    endCombat = false;
            }
            
            if(endCombat)
                endCombat();
        }
    }
    
    public static void startCombat() {
        Collection<MyCharacter> characters = GameUtil.getAllCharactersInWorld();
	for(MyCharacter character : characters) {
	    character.getCharacterStatus().calculateInitiative();
	}
        StateSwitcher.loadCombatState(new LinkedList<CombatActor>(characters));
    }
    
    public static void endCombat() {
        for(MyCharacter aiCharacter : GameUtil.getAllAICharactersInWorld()) {
            if(aiCharacter.getCharacterStatus().getCharacterStatusType() == CharacterStatusType.DEAD) {
                aiCharacter.getPlayer().removeCharacter(aiCharacter);
            }
        }
        StateSwitcher.loadRoamState();
    }
}
